package com.android.driveuploader;

import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.NumberPicker;
import android.widget.Spinner;
import android.widget.Toast;

import com.android.driveuploader.appdatasyncer.AppdataPreferencesSyncer;
import com.android.driveuploader.appdatasyncer.AppdataSyncerService;
import com.android.driveuploader.database.ImagesDBHelper;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.common.AccountPicker;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.ChildList;
import com.google.api.services.drive.model.ChildReference;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.android.driveuploader.appdatasyncer.AppdataPreferencesSyncer.OnChangeListener;
import com.android.driveuploader.appdatasyncer.AppdataPreferencesSyncer.OnUserRecoverableAuthExceptionExceptionListener;


public class MyActivity extends ActionBarActivity implements OnChangeListener,
        OnUserRecoverableAuthExceptionExceptionListener {
    private static final int SYNC_SETTINGS_CODE = 6;
    //public class MyActivity extends GooglePlayServicesActivity {
    public static String open_accountName;
    public static String token;

    public static final String AUTHTOKENSCOPE_DRIVE = "https://www.googleapis.com/auth/drive";
    public static final int ACCOUNT_SELECTED = 3;
    public static final int FOLDER_SELECTED = 4;
    public static final int COMPLETE_AUTHORIZATION_REQUEST_CODE = 55;
    public static Drive driveService;
    public static ArrayList<String> downloadUrl = new ArrayList<String>();
    public static Set<String> albumList = new HashSet<String>();

    public Context context;

    private AppdataPreferencesSyncer mSyncer;
    private SharedPreferences mPreferences;

    private GoogleAccountCredential credential;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPreferences = getSharedPreferences("preferences", MODE_PRIVATE);
        mSyncer = AppdataPreferencesSyncer.get(context);

        // binds an account to the preferences
        //mSyncer.bind(credential, mPreferences);

        // listen changes
        mSyncer.setOnChangeListener(this);

        // listen auth exceptions
        mSyncer.setOnUserRecoverableAuthExceptionListener(this);

        forceSync();


        TinyDB tinyDB = new TinyDB(this);
        if (tinyDB.getString("open_accountName") != "")
            open_accountName = tinyDB.getString("open_accountName");
        Intent wallpaperService = new Intent(this, WallpaperService.class);
        context = this;
        MyActivity.this.startService(wallpaperService);
        Intent useless = new Intent(this, AppdataSyncerService.class);
        startService(useless);

        //Intent googlePS = new Intent(this, GooglePlayServicesActivity.class);
        //startActivity(googlePS);
        //setContentView(R.layout.activity_my);

        setContentView(R.layout.activity_welcome_screen);

        /* Number Picker */

        //TextView numberView = (TextView)findViewById(R.id.textView2);
        NumberPicker numberPicker = (NumberPicker) findViewById(R.id.numberPicker);
        numberPicker.setMaxValue(60);     //  #1
        numberPicker.setMinValue(1);       //  #2
        numberPicker.setWrapSelectorWheel(true);
        numberPicker.setOnValueChangedListener( new NumberPicker.
                OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker picker, int
                    oldVal, int newVal) {
                //numberView.setText("Selected number is "+
                  //      newVal);
            }
        });

        NumberPicker picker2 = (NumberPicker) findViewById(R.id.numberPicker2);
        picker2.setMinValue(0);
        picker2.setMaxValue(4);
        picker2.setDisplayedValues(new String[]{"Seconds", "Minutes", "Hours", "Days", "Week"});


        //Spinner for list of albums.
        getAlbumsList(); //Settings up dataBase.
        Spinner spinner = (Spinner) findViewById(R.id.album_list);
        List<String> list = new ArrayList<String>(albumList);
        ArrayAdapter dataAdapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item, list);
// Specify the layout to use when the list of choices appears
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
        spinner.setAdapter(dataAdapter);

    }

    private void forceSync() {
        new ForceSyncAsyncTask().execute();
    }

    /**
     * Browse a album from local fodlers
     * @param view
     */

    public void openFromGallery(View view) {
        /* Workes with Google Photos. So minSdk = 19 required.
        Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        startActivityForResult(i, 34);
        */

        // which image properties are we querying
        //ArrayList<String> albumList = new ArrayList<String>();

        getAlbumsList();

        //Save images from a specific gallery to Database? //TODO:
        saveImagesFromAlbumToDatabase("Screenshots");
    }

    private void saveImagesFromAlbumToDatabase(String albumName) {
        //Temp name set
        //albumName = "Camera";
        String[] projection = new String[]{
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                MediaStore.Images.Media.DATA,
        };

        // Get the base URI for the People table in the Contacts content provider.
        Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        // Make the query.
        //Cursor cur = managedQuery(images,
        Cursor cur = getContentResolver().query(images,
                projection, // Which columns to return
                "",         // Which rows to return (all rows)
                null,       // Selection arguments (none)
                ""          // Ordering
        );

        ImagesDBHelper database = new ImagesDBHelper(context);

        if (cur.moveToFirst()) {
            String bucket; //ALBUM NAME
            String filePath = ""; //File Path
            int bucketColumn = cur.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
            int data = cur.getColumnIndex(MediaStore.Images.Media.DATA);

            do {
                // Get the field values
                bucket = cur.getString(bucketColumn);
                filePath = cur.getString(data);

                //albumList.add(bucket); //Get the album list; Local..
                if (bucket.equalsIgnoreCase(albumName)) {
                    Log.i("$$$", "'" + bucket + "'");
                    database.insertFile(bucket, filePath, "device");
                }

                // Do something with the values.
                //Log.i("^^^^^^^^^^^^^^^^^^^^^^^^^", filePath);
            } while (cur.moveToNext());
            Log.i("List of albums*******", albumList.toString());

        }
    }

    private void getAlbumsList() {
        String[] projection = new String[]{
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                MediaStore.Images.Media.DATE_TAKEN,
                MediaStore.Images.Media.DISPLAY_NAME,
                MediaStore.Images.Media.DATA,
        };

        // Get the base URI for the People table in the Contacts content provider.
        Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;


        // Make the query.
        //Cursor cur = managedQuery(images,
        Cursor cur = getContentResolver().query(images,
                projection, // Which columns to return
                "",         // Which rows to return (all rows)
                null,       // Selection arguments (none)
                ""          // Ordering
        );

        Log.i("ListingImages"," query count="+cur.getCount());

        if (cur.moveToFirst()) {
            String bucket; //ALBUM NAME
            String filePath = ""; //File Path
            int bucketColumn = cur.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
            int data = cur.getColumnIndex(MediaStore.Images.Media.DATA);

            do {
                // Get the field values
                bucket = cur.getString(bucketColumn);
                filePath = cur.getString(data);

                albumList.add(bucket); //Get the album list; Local.. TODO

                // Do something with the values.
                Log.i("^^^^^^^^^^^^^^^^^^^^^^^^^", filePath);
            } while (cur.moveToNext());
            Log.i("List of albums*******", albumList.toString());

        }
    }
    private void storeAlbumImagesToDatabase(String albumName) {
    }

    public void printDatabaseToLog(View view) {
        ImagesDBHelper imagesDBHelper = new ImagesDBHelper(context);
        ArrayList<HashMap<String, String>> imagesList =  imagesDBHelper.getAllImages();
        int i = 0;
    }

    class ForceSyncAsyncTask extends AsyncTask<Void, Boolean, Boolean> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //mSaveButton.setEnabled(false);
        }
        @Override
        protected Boolean doInBackground(Void... params) {
            mSyncer.sync();
            return true;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            //mSaveButton.setEnabled(true);
            refresh();
        }
    }

    /**
     * Refreshes the screen with the preferences stored
     * in the local {@code SharedPreferences} preferences.
     * TODO: this has tobe updated for drive related code. As of now un-usable for me.
     */
    private void refresh() {
        //Log.d(TAG, "Refreshing the screen");
        //final float rating = mPreferences.getFloat(KEY_RATING, 0);
        //final String name = mPreferences.getString(KEY_NAME, "");

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.i("RUNNING AFTER SYNC -->>>>>>", mPreferences.getString(KEY_SELECTED_FOLDER_ID, "-1"));
                //mRatingBar.setRating(rating);
                //mNameEditText.setText(name);
            }
        });
    }

    /**
     * Saves the values in the local preferences.
     */
    private void save() {
        // write to the preferences
        mPreferences.edit()
                .putString(KEY_SELECTED_FOLDER_ID, "")
                //.putString(KEY_NAME, mNameEditText.getText() + "")
                .commit();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Intent googlePS = new Intent(this, GooglePlayServicesActivity.class);
            startActivityForResult(googlePS, 4);
            return true;
        }
        if (id == R.id.action_settings_activity) {
            Intent syncSettings = new Intent(this, SettingsActivity.class);
            startActivityForResult(syncSettings, SYNC_SETTINGS_CODE);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public void openDriveFolderList(View view) {
        /*Intent openDrive = new Intent(this, OpenDriveFolderList.class);
        startActivityForResult(openDrive, 3);*/
        if (MyActivity.open_accountName == null) {
            chooseAccount();
        } else {
            pickFolder();
        }
    }

    private void pickFolder() {
        Intent pickFolder = new Intent(this, PickFolderWithOpenerActivity.class);
        startActivityForResult(pickFolder, FOLDER_SELECTED);
    }

    public void chooseAccount() {
        Intent chooseAccountIntent = AccountPicker.newChooseAccountIntent(
                null, // selectedAccount
                null, // allowableAccounts
                new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, // allowableAccountTypes
                false, // alwaysPromptForAccount
                null, // descriptionOverrideText
                MyActivity.AUTHTOKENSCOPE_DRIVE, // addAccountAuthTokenType
                null, // addAccountRequiredFeatures
                null // addAccountOptions
        );
        startActivityForResult(chooseAccountIntent, ACCOUNT_SELECTED);
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == 4) {

        } else if (resultCode == 3) {

        }
        if (requestCode == ACCOUNT_SELECTED) {
            if (resultCode == RESULT_OK) {
                MyActivity.open_accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                new TinyDB(this).putString("open_accountName", data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME));
                Log.i("TOKEN: ", open_accountName);
                pickFolder();
                //startAuthenticatedUpload(MyActivity.open_accountName);
            }else {
                Toast.makeText(this, "Problem picking account", Toast.LENGTH_LONG).show();
            }
        }
        if (requestCode == FOLDER_SELECTED) {
            String id = data.getStringExtra("folder_id");
            mPreferences.edit().putString(KEY_SELECTED_FOLDER_ID, id).commit(); //TODO: saving folder id to preferences
            Log.i("YEP!!!!:>>>>>>>>>>>>>>>>>>>>> ", id);
            //forceSync(); //TODO: try saying the settings to online. Implementation later.
            Log.i("YEP!!!!: " , String.valueOf(resultCode));
            readFilesFromFolder(open_accountName, id);
            Log.i("Google Drive Android FULL API.......", "PASS.........");
        }
        if (requestCode == COMPLETE_AUTHORIZATION_REQUEST_CODE) {
            Log.i("Google Drive Android FULL API.......", "..........PASS");
        }
    }

    private void readFilesFromFolder(final String accountName, final String folderId) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                doAuthenticatedUpload(accountName, folderId);
                return null;
            }

            private void doAuthenticatedUpload(String accountName, String folderId) {

                credential = GoogleAccountCredential.usingOAuth2(MyActivity.this, Collections.singleton(DriveScopes.DRIVE));
                credential.setSelectedAccountName(open_accountName);
                driveService = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential).build();

                try {
                    // Try to perform a Drive API request, for instance:
                    //FileList file = driveService.files().list().execute();//.insert(body, mediaContent).execute();
                    //ChildList list = driveService.children().list("root").execute();
                    //retrieveFilesFromFolder(driveService, ""); //TODO: need to send folder ID
                    //printFilesInFolder(driveService, folderId);
                    printImageFilesInFolder(driveService, folderId);
                    //WallpaperScheduler wps = new WallpaperScheduler(5); //TODO: working code
                    //wps.changeWallPapers(MyActivity.this, driveService, downloadUrl, 1, TimeUnit.MINUTES); //TODO: working code.
                    //  Intent wallpaperService = new Intent(MyActivity.this, WallpaperIntentService.class);
                    //  MyActivity.this.startService(wallpaperService);
                    //Intent wallpaperService = new Intent(MyActivity.this, WallpaperService.class);
                    //MyActivity.this.startService(wallpaperService);

                    //Log.i("List", list.toString());
                } catch (UserRecoverableAuthIOException e) {
                    MyActivity.this.startActivityForResult(e.getIntent(), COMPLETE_AUTHORIZATION_REQUEST_CODE);
                } catch (IOException e) {
                    e.printStackTrace();
                }


                /*
                try {
                    MyActivity.token = GoogleAuthUtil.getToken(MyActivity.this,
                            accountName, "oauth2:" + MyActivity.AUTHTOKENSCOPE_DRIVE);
                    Log.i("token = ", MyActivity.token);
                    Log.i("Folder id = ", folderId);
                } catch (UserRecoverableAuthException userAuthEx) {
                    // This is an authentication error that we can recover from.
                    return;
                } catch (GoogleAuthException e) {
                    Log.e("@@@", "GoogleAuthException", e);
                    return;
                } catch (IOException e) {
                    Log.e("###", "IOException", e);
                    return;
                } */

            }
        }.execute();
    }

    public List<File> retrieveFilesFromFolder(Drive service, String folderID) throws IOException {
        List<File> result = new ArrayList<File>();
        Drive.Files.List request = service.files().list();
        //Drive.Children.List request = service.children().list(folderID);

        do {
            try {
                FileList files = request.execute();
                //ChildList files = request.execute();
                result.addAll(files.getItems());
                request.setPageToken(files.getNextPageToken());
            } catch (IOException e) {
                System.out.println("An error occurred: " + e);
                request.setPageToken(null);
            }
        } while (request.getPageToken() != null &&
                request.getPageToken().length() > 0);
        return result;
    }

    /**
     * Print files belonging to a folder.
     *
     * @param service Drive API service instance.
     * @param folderId ID of the folder to print files from.
     */
    private static void printFilesInFolder(Drive service, String folderId)
            throws IOException {
        String MIME_TYPE_IMAGE = "mimeType = 'application/vnd.google-apps.photo'";
        Drive.Children.List request = service.children().list(folderId);
        //TODO: Image mime_type works only with Files.list();
        //Drive.Children.List request = service.files().list(folderId).setQ(MIME_TYPE_IMAGE);

        do {
            try {
                ChildList children = request.execute();

                for (ChildReference child : children.getItems()) {
                    //System.out.println("File Id: " + child.getId());
                    Log.i("File Id: " , child.getId());
                }
                request.setPageToken(children.getNextPageToken());
            } catch (IOException e) {
                //System.out.println("An error occurred: " + e);
                Log.i("An error occurred: " , e.toString());
                request.setPageToken(null);
            }
        } while (request.getPageToken() != null &&
                request.getPageToken().length() > 0);
    }

    /**
     * Print files belonging to a folder.
     *
     * @param service Drive API service instance.
     * @param folderId ID of the folder to print files from.
     */
    private void printImageFilesInFolder(Drive service, String folderId)
            throws IOException {
        //String MIME_TYPE_IMAGE = "mimeType = 'application/vnd.google-apps.document'";
        String MIME_TYPE_IMAGE = "mimeType = 'image/jpeg'";
        String QUERY_TYPE_PARENTS = "'" + folderId + "' in parents";
        //Drive.Files.List request = service.files().list().setQ(QUERY_TYPE_PARENTS).setQ(MIME_TYPE_IMAGE);
        Drive.Files.List request = service.files().list().setQ(QUERY_TYPE_PARENTS + " and " + MIME_TYPE_IMAGE);
        //Drive.Files.List request = service.files().list().setQ(MIME_TYPE_IMAGE);
        //TODO: Image mime_type works only with Files.list();
        //Drive.Children.List request = service.files().list(folderId).setQ(MIME_TYPE_IMAGE);

        //TRY TO add image URLs into appDataBase......
        ImagesDBHelper imagesDBHelper = new ImagesDBHelper(context);

        do {
            try {
                FileList children = request.execute();

                for (File child : children.getItems()) {
                    //System.out.println("File Id: " + child.getId());
                    //Log.i("File Id: " , child.getId());
                    Log.i("File Id: ", child.getTitle());
                    downloadUrl.add(child.getDownloadUrl()); //TODO: Adding Image URLs to downloadUrl arrayList here....
                    imagesDBHelper.insertFile(folderId, child.getDownloadUrl(), "googledrive");
                }
                request.setPageToken(children.getNextPageToken());
            } catch (IOException e) {
                //System.out.println("An error occurred: " + e);
                Log.i("An error occurred: " , e.toString());
                request.setPageToken(null);
            }
        } while (request.getPageToken() != null &&
                request.getPageToken().length() > 0);
        saveArrayList(downloadUrl);
    }

    private void saveArrayList(ArrayList<String> downloadUrlList) {
        TinyDB db = new TinyDB(this);
        db.putList("downloadUrls", downloadUrlList);
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i("ACTIVITY STOPPED", "************************************");
    }

    @Override
    public void onChange(SharedPreferences prefs) {

    }

    @Override
    public void onUserRecoverableAuthException(UserRecoverableAuthIOException ex) {

    }

    private static final String TAG = "MY_ACTIVITY";
    private static final String KEY_SELECTED_FOLDER_ID = "rating";
    private static final String KEY_FREQUENCY = "name";

}